/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the ViewMyCurrency extension.
 *
 * The Initial Developer of the Original Code is
 * Will Moffat.
 * Portions created by the Initial Developer are Copyright (C) 2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

//dump("// $Id: WILL_Currency.js,v 1.65 2007/03/26 09:30:08 Will Exp $\n");

//WILL: TODO: add detection for sepeator in arguements - warn

////////////////////////////////////////////////////////////////////////////////
VMC.Currency = function(country,description,code,displaySymbol,formula) {
////////////////////////////////////////////////////////////////////////////////
  if (!arguments || !arguments.length || !(arguments.length==1 || arguments.length==5)) { throw "Require 1 string or 5 args to initialise Currency"; }
  if (arguments[0] && arguments[0]=='empty') { return this; } // for testbench

  var SEPARATOR='-';
  this.toString=toString;
  this.toSerial=toSerial;
  this.isValid=isValid;
  this.equals=equals;
  this.completelyEquals = completelyEquals;
  this._createFromString=_createFromString;
  this.getHtml=getHtml;
  this.formula = formula; // formula used to calculate relative value e.g. BEF has '40*EUR'
  this.getFormulaCurrencyCode = getFormulaCurrencyCode;
  this.getFormulaRate         = getFormulaRate;

  this.isCalculatedRate = false; 
 


  if (arguments.length==1) {
    this._createFromString(arguments[0]); //the first arg is the complete string
  } else {
    this.country=country;
    this.description=description;
    this.code=code;
    this.displaySymbol=displaySymbol;
    var testStr=country+description+country+displaySymbol;
    if (testStr.match(SEPARATOR)) { VMC.log('ERR','Attempt to create currency '+this.toString(false)+' with separator symbol "'+SEPARATOR+'" in it.'); }
  }
  this.error='';

  this.isValid();

  var parseFormulaFunc = function(formula) {
    var r=/^=(\d+\.?\d*)\s(\D+)$/.exec(formula);
    if (!r) { VMC.log('WARN','bad formula '+formula); return null; }
    r.shift(); // throw away the match
    return r; // return 12.34 , EUR
  };
  
  function getFormulaRate()         { return parseFormulaFunc(this.formula)[0]; }
  function getFormulaCurrencyCode() { return parseFormulaFunc(this.formula)[1]; }
    

  function getHtml() {
    return this.displaySymbol;
  }

  function _createFromString(s) {
    if (!s) { throw 'Tried to create a currency from null string'; }

    s=unescape(s);
    var bits=s.split(SEPARATOR);
    if (bits.length < 4) { throw 'Tried to create a currency from invalid string '+s; }
    this.country=bits.shift();
    this.description=bits.shift();
    this.code=bits.shift();
    this.displaySymbol=bits.shift();
    this.formula = bits.shift();
  }
      

  function toString(encoded) {
    var s;
    switch(encoded) {
    case true:
      // encode for storage
      s=[this.country,this.description,this.code,this.displaySymbol,this.formula].join(SEPARATOR);
      s=escape(s);
      break;
    case false:
      // verbose mode for human
      s=this.description+' ( '+this.code+' '+this.getHtml()+' )';
      break;
    default:
      //simple human readable form if toString() called
      s=this.code+' '+this.getHtml(); 
    }
    return s;
  }

  function toSerial() { return 'new Currency("'+country+'","'+description+'","'+code+'","'+displaySymbol+'","'+formula+'")'; }

  function isValid() {
    //WILL: TODO: check for separator
    var err='';
    if (!this.country || !this.description || !this.code || !this.displaySymbol) {
      VMC.log('ERR','Currency: '+this+' is missing entries');
      return false;
    }

    if (!this.code.length || this.code.length != 3) { 
      err += '\n Code "'+this.code+'" should be 3 letters (example: USD or EUR)';
    }
    //WILL: TODO: put validation back in
    //if (this.symbol.length < 1) err=err+'\n Symbol "'+this.symbol+'" should be at least 1 letter (example: $ or \\u02a3)';
    //if (this.html.length   < 1) err=err+'\n Html "'+this.html+'" should be at least 1 letter (example: $ or &euro;)';
    this.error=err;
    if (err) { return false; }
    else     { return true;  }
  }

  function equals(c) { // are these currencies equivalent (do they have the same code)
    if (this==c) { return true; }
    else if (!c) { return false; }
    else         { return (this.code == c.code); }
  }

  function completelyEquals(c) { // additional test, do they have the same country?
    if (!this.equals(c))           { return false; }
    if (this.country != c.country) { return false; }
    return true;
  }

  return this; // end VMC.Currency()
};

VMC.isArray = function() {
  if (typeof arguments[0] == 'object') { 
    var criterion =  arguments[0].constructor.toString().match(/array/i); 
    return (criterion !== null); 
  }
  return false;
};


////////////////////////////////////////////////////////////////////////////////
VMC.CurrencyList = function(items) {
////////////////////////////////////////////////////////////////////////////////
  this.initFrom(items);
};

VMC.CurrencyList.prototype.SEPARATOR=',';

VMC.CurrencyList.prototype.initFrom = function(newItems) {
    if (newItems) {
      if (newItems instanceof VMC.CurrencyList) { this._createFromCurrencyList(newItems); } //create from another CurrencyList
      else if (VMC.isArray(newItems))           { this.items=newItems; }                    //create from array
      else if (typeof newItems == 'string')      { this._createFromString(newItems); }       //create from string
      else { VMC.log('ERR','Tried to create currency list from invalid args '+newItems); }
    } else {
      this.items=[];
    }
};

VMC.CurrencyList.prototype._applyFunc = function(func) {  //WILL: TODO: this isn't private so rename it
  for (var i=0, len=this.items.length; i<len; i++) {
      func(this.items[i]);
    }
};
    
// (_checkAllUnique was removed in v1.58 because the conversion profiles now give a sane way to cope with currencies with the same symbols)


VMC.CurrencyList.prototype._createFromCurrencyList = function(currList) {
    VMC.CurrencyList.prototype.isValid(currList);
    if (this==currList) { VMC.log('ERR','Trying to update list from itself!'); }
    this.items=currList.items;
};
  
  // no checking for duplicates
VMC.CurrencyList.prototype._createFromString = function(s) {
    var items=[];
    var currlist_str=s.split(VMC.CurrencyList.prototype.SEPARATOR);
    var curr;
    for (var i=0; i<currlist_str.length; ++i) {
      curr=new VMC.Currency(currlist_str[i]);
      items.push(curr);
    }
    this.items=items;
};

VMC.CurrencyList.prototype.toString = function(encode) { //WILL: TODO: does this need a serialization??
    var s='';
    if (!this.items || !this.items.length) { return s; } //it's possible to have an empty list

    var sep_str=this.SEPARATOR; //WILL: what's wrong with? VMC.CurrencyList.prototype.SEPARATOR
    if (!encode) { sep_str +=' '; } //add a space if this is for humans

    for (var i=0; i<this.items.length-1;i++) {
      s=s+this.items[i].toString(encode)+sep_str;
    }
    s=s+this.items[i].toString(encode); //no comma at end
    return s;
};

VMC.CurrencyList.prototype.createListFromCodes = function(codes) {
  var currencyList = new VMC.CurrencyList();
  for (var i=0;i<codes.length;i++) {
    currencyList.add(this.findFromCode(codes[i]));
  }
  return currencyList;
};
		
VMC.CurrencyList.prototype.findFromCode = function(code,failSilently) {
  if (!code) { return null; } // we could be disabled
    for (var i=0; i<this.items.length; ++i) {
      if (this.items[i].code==code) { return this.items[i]; }
    }
    if (!failSilently) { VMC.log('ERR','failed to find '+code+' in list'); }
    return null;
};



//WILL: Like indexOf but compares by currency.code
VMC.CurrencyList.prototype.findIndexByCode = function(currency) {
    var array=this.items;
    if (!array) { return -1; }
    var index=-1;
    for (var i=0, len=array.length; i<len; i++) {
      if (array[i].equals(currency)) { index=i; }
    }
    return index;
};
  
VMC.CurrencyList.prototype.existsInList = function(currency) {
    if (this.findIndexByCode(currency)==-1) { return false; }
    return true;
};

VMC.CurrencyList.prototype.addList = function(otherCurrencyList,allowDups,failSilently) {
  var self = this;
  otherCurrencyList._applyFunc( function(currency) { self.add(currency,allowDups,failSilently); } );
};

VMC.CurrencyList.prototype.removeList = function(otherCurrencyList) {
  var self = this;
  otherCurrencyList._applyFunc( function(currency) { self.remove(currency); } );
};

VMC.CurrencyList.prototype.add = function(currency,allowDups,failSilently) {
  if (this.existsInList(currency)) {
    if (!allowDups) {
      if (!failSilently) { VMC.log('ERR',currency+' is already in this list'); }
      return false;
    }
  }
  this.items.push(currency);
  return true;
};

    
VMC.CurrencyList.prototype.remove = function(currency) {
    var array=this.items;
    var delIndex=this.findIndexByCode(currency);
      
    if (delIndex==-1) {VMC.alert('Failed to find '+currency+' in '+this); return false; }
    
    for (var i=delIndex;i<array.length-1;i++) {
      array[i]=array[i+1];
    }
    array.length--;
    return true;
};

  // null is also returned if we get to the end. This should disable us
VMC.CurrencyList.prototype.getNext = function(oldItem) {
    var index;

    if (!oldItem) {
      index=-1;
    } else {
      index=this.findIndexByCode(oldItem);
      if (index==-1) {VMC.alert('Failed to find '+oldItem+' in '+this); return null; }
    }
    
    var nextItem=null;
    index++;
    if (index<this.items.length) { nextItem=this.items[index]; }
    
    return nextItem;
};


VMC.CurrencyList.prototype.isEmpty = function() {
  return (this.items.length===0);
};


VMC.CurrencyList.prototype.isValid = function (currList,failSilently) {
  var error;
  if      (!currList)              { error='Null list'; }
  else if (!currList.items)        { error='null CurrencyList.items'; }
  else if (!currList.items.length) { error='CurrencyList.items is empty'; }

  if (error && !failSilently) { VMC.log('ERR',error); }
  if (error) { return false; }
  return true;
};
    


VMC.CurrencyList.prototype.matchBoundary = '[\\s\\d\\(\\)<>=.,-\\\\]';

//WILL: TODO: see if I support http://www.alanwood.net/unicode/currency_symbols.html

////////////////////////////////////////////////////////////////////////////////
VMC.SymbolList = function(symbols) {
////////////////////////////////////////////////////////////////////////////////
  this.symbols = symbols;
};
VMC.SymbolList.prototype.toString = function() { return 'new SymbolList(["'+this.symbols.join('","')+'"])'; };
VMC.SymbolList.prototype.matches  = function(str) { return (this.symbols.indexOf(str) != -1); };

////////////////////////////////////////////////////////////////////////////////
VMC.SymbolTableEntry = function(currency,symbolList) {
////////////////////////////////////////////////////////////////////////////////
  this.currency = currency;
  this.symbolList = symbolList;
};
VMC.SymbolTableEntry.prototype.toString = function() { return '       new SymbolTableEntry('+this.currency.toSerial()+','+this.symbolList+')'; };

////////////////////////////////////////////////////////////////////////////////
VMC.SymbolTable = function(list) {
////////////////////////////////////////////////////////////////////////////////
  this.entries = list;
  this._symbol2currencyHash = null;
};

VMC.SymbolTable.prototype.toString = function() {  return 'new SymbolTable([\n'+this.entries.join(',\n')+'])'; };

VMC.SymbolTable.prototype.lookupCurrency = function(currency) {
  var toEachEntry = function(entry) {
    if (entry.currency.completelyEquals(currency)) { return entry; }
    else {  return undefined;  }
  };
  return VMC.applyFuncToArray(toEachEntry,this.entries);
};

VMC.SymbolTable.prototype._updateHash = function(forceUpdate) {
  if (this._symbol2currencyHash && !forceUpdate) { return; }

  this._symbol2currencyHash = {};
  var hash = this._symbol2currencyHash;
  var currentCurrency;
  
  var toEachSymbol = function(symbol) { symbol = symbol.toLowerCase(); if (!hash[symbol]) {hash[symbol]=currentCurrency;} };
  var toEachEntry = function(entry) {
    currentCurrency = entry.currency;
    VMC.applyFuncToArray(toEachSymbol,entry.symbolList.symbols);
  };
  
  // only use first instance of each symbol (warn if dup?)
  VMC.applyFuncToArray(toEachEntry,this.entries);
};

// search through the symbol lists in order
VMC.SymbolTable.prototype.matches = function(str) {
  this._updateHash();
  return this._symbol2currencyHash[str.toLowerCase()] || null;  //TODO: consider if we should warn if missing? //WILL: TODO: consider implications of case insensitivity
};

VMC.SymbolTable.prototype._validPosition = function(pos, endOK) {
  if (endOK && pos==this.entries.length) { return; } // adding to new end position is allowed
  if (pos<0 || pos>=this.entries.length) { throw "invalid position: "+pos+". Must be between 0 and less than "+this.entries.length; }
};

//move item at positionA above item at positionB
VMC.SymbolTable.prototype.move = function(posA,posB) {
  this._validPosition(posA);
  this._validPosition(posB);
  if (! posA>posB ) { throw "itemA to be moved must be below (greater index) than itemB"; }
  var entryA   = this.entries.splice(posA,1)[0];    // remove 1 item at posA
  this.entries.splice(posB,0,entryA);               // now remove 0 items and insert old item at posB
  this._symbol2currencyHash = null; // mark dirty
};

//remove item at positionA
VMC.SymbolTable.prototype.remove = function(posA) {
  this._validPosition(posA);
  this.entries.splice(posA,1);
  this._symbol2currencyHash = null; // mark dirty
};

//add item at positionA
VMC.SymbolTable.prototype.add = function(entry,posA) {
  if (posA === undefined) { posA = this.entries.length; } // if position not specified then append
  this._validPosition(posA, true /*endOK*/);
  this.entries.splice(  posA,0,entry);
  this._symbol2currencyHash = null; // mark dirty
};

VMC.SymbolTable.prototype.createRegExps = function() {

  this._updateHash();
    // now that we've built the associateArray, remember the keys (symbols) sorted by longest to shortest length
    // needed for regexp matching priority
    var sortByKeyLength = function(associateArray) {
      var keys=[];
      for (var k in associateArray) { keys.push(k); }
      keys.sort( function(a,b) { return (b.length-a.length); });
      return keys;
    };

    var symbolList=sortByKeyLength(this._symbol2currencyHash);
    var SEPERATOR = '\v';
    var SEPERATOR_RE = /\v/g;
    var matchCurr=symbolList.join(SEPERATOR);

    // IMPORTANT - since single quotes are also interpolated in Javacript \b must be written '\\b'
    matchCurr = matchCurr.replace(/([.?|\[\]\/^$*+\\{}()])/g , '\\$1');			
    matchCurr = matchCurr.replace(SEPERATOR_RE, '|'); //now that we have escaped | in symbols, we can use it in our regexp
    matchCurr = '(' + matchCurr + ')';
    var matchNumber='((?:\\d[\\d, .]*\\d)|\\d)'; // multiple digit/SPACE/comma/point starting & ending in digit OR single digit (with less priority)
    var matchSpace='(\\s*)';      //optional

    var newCompiledRegexp = function(regexpStr,flags) {
      var regexp = new RegExp().compile(regexpStr, flags); // Multi-line, case-Insensitive, Global
      VMC.log('DBG3','complied regexp='+regexp.toSource());
      return regexp;
    };

    var matchBoundary = VMC.CurrencyList.prototype.matchBoundary; //TODO: check this reference
    var matchStartOrBoundary = '('+matchBoundary+'|^)'; 
    var matchEndOrBoundary   = '('+matchBoundary+'|$)';

    // since the digits have already been found, they are anchored to that match using $ and ^
    //these forms don't include the number:
    this.currencyLeftRE   = newCompiledRegexp( matchStartOrBoundary + matchCurr + matchSpace +'$' , 'i'); //not global
    this.currencyRightRE  = newCompiledRegexp( '^' + matchSpace + matchCurr + matchEndOrBoundary   , 'i'); //only used for matching one currency
};				  



////////////////////////////////////////////////////////////////////////////////



// WILL: if I change Euro or Dollar for one country then symbols then I need to change them everywhere. Is there a better way?
// if includeNotSupported=true then return all currencies I know about, even if they don't have a webservice
// (the symbol used to display the converted amount defaults to the first symbol)
VMC.CurrencyDataBase = function(includeNotSupported) { 
  var currentCurrencies=[
['Afghanistan',			'Afghan afghani',			'AFN',	'\u060B' ],
['Albania',				'Albanian lek',			'ALL',	'L' ],
['Algeria',				'Algerian dinar',			'DZD',	'\u062F.\u062C' ],
['Andorra',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Angola',				'Angolan kwanza',			'AOA',	'Kz' ],
['Anguilla',				'East Caribbean dollar',		'XCD',	'$' ],
['Antigua and Barbuda',			'East Caribbean dollar',		'XCD',	'$' ],
['Argentina',				'Argentine peso',			'ARS',	'$' ],
['Armenia',				'Armenian dram',			'AMD',	'\u0564\u0580.' ],
['Aruba',				'Aruban florin',			'AWG',	'\u0192' ],
['Australia',				'Australian dollar',			'AUD',	'$','A$','AU $','AUD $','AUD$', '$AU' ],
['Austria',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Azerbaijan',				'Azerbaijani manat',			'AZN',	'man.','\u043C\u0430\u043D.' ],
['Bahamas',				'Bahamian dollar',			'BSD',	'$' ],
['Bahrain',				'Bahraini dinar',			'BHD',	'\u0628.\u062F' ],
['Bangladesh',				'Bangladeshi taka',			'BDT',	'\u09F2','\u09F3' ],
['Barbados',				'Barbados dollar',			'BBD',	'$' ],
['Belarus',				'Belarusian ruble',			'BYR',	'\u0440.' ],
['Belgium',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Belize',				'Belize dollar',			'BZD',	'$' ],
['Benin',				'CFA franc BCEAO',			'XOF',	'Fr' ],
['Bermuda',				'Bermuda dollar',			'BMD',	'$' ],
['Bhutan',				'Bhutanese ngultrum',			'BTN',	'Nu' ],
['Bolivia',				'Bolivian boliviano',			'BOB',	'b$' ],
['Bosnia and Herzegovina',		'Bosnia and Herzegovina convertible mark',	'BAM',	'KM','\u041A\u041C' ],
['Botswana',				'Botswana pula',			'BWP',	'P' ],
['Brazil',				'Brazilian real',			'BRL',	'R$' ],
['British Indian Ocean Territory',	'British pound',			'GBP',	'\u00A3','quid' ],
['British Virgin Islands',		'United States dollar',			'USD',	'$','dollars','US$','US $' ],
['Brunei',				'Brunei dollar',			'BND',	'$' ],
['Bulgaria',				'Bulgarian lev',			'BGN',	'\u043B\u0432' ],
['Burkina Faso',			'CFA franc BCEAO',			'XOF',	'Fr' ],
['Burundi',				'Burundi franc',			'BIF',	'Fr' ],
['Cambodia',				'Cambodian riel',			'KHR',	'\u17DB' ],
['Cameroon',				'CFA franc BEAC',			'XAF',	'Fr' ],
['Canada',				'Canadian dollar',			'CAD',	'$','C $','CDN$','C$','CA$' ],
['Cape Verde',				'Cape Verdean escudo',			'CVE',	'Esc' ],
['Cayman Islands',			'Cayman Islands dollar',		'KYD',	'$' ],
['Central African Republic',		'CFA franc BEAC',			'XAF',	'Fr' ],
['Chad',				'CFA franc BEAC',			'XAF',	'Fr' ],
['Chile',				'Chilean peso',			'CLP',	'$' ],
['China, People\'s Republic of',	'Chinese yuan (renminbi)',		'CNY',	'\u5143','\u5706','Yuan' ],
['Cocos (Keeling) Islands',		'Australian dollar',			'AUD',	'$','A$','AU $' ],
['Colombia',				'Colombian peso',			'COP',	'$','COL$','\u20B1' ],
['Comoros',				'Comorian franc',			'KMF',	'Fr' ],
['Congo, Democratic Republic of the',	'Congolese franc',			'CDF',	'Fr' ],
['Congo, Republic of the',		'CFA franc BEAC',			'XAF',	'Fr' ],
['Cook Islands',			'New Zealand dollar',			'NZD',	'$' ],
['Costa Rica',				'Costa Rican col\u00F3n',		'CRC',	'\u20A1' ],
['C\u00F4te d\'Ivoire',			'CFA franc BCEAO',			'XOF',	'Fr' ],
['Croatia',				'Croatian kuna',			'HRK',	'kn' ],
['Cuba',				'Cuban convertible peso',		'CUC',	'$' ],
['Cyprus',				'Cypriot pound',			'CYP',	'\u00A3' ],
['Czech Republic',			'Czech koruna',			'CZK',	'K\u010D' ],
['Denmark',				'Danish krone',			'DKK',	'kr.','kr' ],
['Djibouti',				'Djiboutian franc',			'DJF',	'Fr' ],
['Dominica',				'East Caribbean dollar',		'XCD',	'$' ],
['Dominican Republic',			'Dominican peso',			'DOP',	'$','\u20B1' ],
['East Timor',				'United States dollar',			'USD',	'$','dollars','US$','US $' ],
['Ecuador',				'United States dollar',			'USD',	'$','dollars','US$','US $' ],
['Egypt',				'Egyptian pound',			'EGP',	'\u00A3','\u062C.\u0645' ],
['El Salvador',			'El Salvadoran col\u00F3n',		'SVC',	'\u20A1' ],
['Equatorial Guinea',			'CFA franc BEAC',			'XAF',	'Fr' ],
['Eritrea',				'Eritrean nakfa',			'ERN',	'Nfk' ],
['Estonia',				'Estonian kroon',			'EEK',	'KR' ],
['Ethiopia',				'Ethiopian birr',			'ETB',	'Br' ],
['Eurozone',                            'Euro',                                 'EUR',  '\u20AC','euros','euro' ],
['Falkland Islands',			'Falkland pound',			'FKP',	'\u00A3' ],
['Fiji',				'Fijian dollar',			'FJD',	'$' ],
['Finland',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['France',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['French Polynesia',			'CFP franc',				'XPF',	'\u20A3' ],
['Gabon',				'CFA franc BEAC',			'XAF',	'Fr' ],
['Gambia, The',			'Gambian dalasi',			'GMD',	'D' ],
['Georgia',				'Georgian lari',			'GEL',	'\u10da\u10d0\u10e0\u10d8' ],
['Germany',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Ghana',				'Ghanaian cedi',			'GHC',	'\u20B5' ],
['Gibraltar',				'Gibraltar pound',			'GIP',	'\u00A3' ],
['Greece',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Grenada',				'East Caribbean dollar',		'XCD',	'$' ],
['Guatemala',				'Guatemalan quetzal',			'GTQ',	'Q' ],
['Guernsey',				'Guernsey pound',			'GGP',	'\u00A3' ],
['Guinea',				'Guinean franc',			'GNF',	'Fr' ],
['Guinea Bissau',			'CFA franc BCEAO',			'XOF',	'Fr' ],
['Guyana',				'Guyanese dollar',			'GYD',	'$' ],
['Haiti',				'Haitian gourde',			'HTG',	'G' ],
['Honduras',				'Honduran lempira',			'HNL',	'L' ],
['Hong Kong',				'Hong Kong dollar',			'HKD',	'$','\u5713' ],
['Hungary',				'Hungarian forint',			'HUF',	'Ft','Ft.' ],
['Iceland',				'Icelandic kr\u00F3na',			'ISK',	'kr','kr.' ],
['India',				'Indian rupee',			'INR',	'\u20A8','Rs','Rs.' ],
['Indonesia',				'Indonesian rupiah',			'IDR',	'\u20A8' ],
['Iran',				'Iranian rial',			'IRR',	'\u0631\u064A\u0627\u0644' ],
['Iraq',				'Iraqi dinar',			'IQD',	'\u0639.\u062F' ],
['Ireland, Republic of',			'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Isle of Man',			'Isle of Man pound',			'IMP',	'\u00A3' ],
['Israel',				'New Israeli sheqel',			'ILS',	'\u20AA' ],
['Italy',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Jamaica',				'Jamaican dollar',			'JMD',	'$' ],
['Japan',				'Japanese yen',			'JPY',	'\u00A5','\uFFE5','\u5186','yen' ],
['Jersey',				'Jersey pound',			'JEP',	'\u00A3' ],
['Jordan',				'Jordanian dinar',			'JOD',	'\u062F.\u0627' ],
['Kazakhstan',				'Kazakhstani tenge',			'KZT',	'T' ],
['Kenya',				'Kenyan shilling',			'KES',	'S' ],
['Kiribati',				'Australian dollar',			'AUD',	'$','A$','AU $' ],
['Korea, North',			'North Korean won',			'KPW',	'\u20A9', '\uC6D0' ],
['Korea, South',			'South Korean won',			'KRW',	'\u20A9', '\uC6D0' ],
['Kosovo',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Kuwait',				'Kuwaiti dinar',			'KWD',	'\u062F.\u0643' ],
['Kyrgyzstan',				'Kyrgyzstani Som',			'KGS',	'\u0441\u043E\u043C' ],
['Laos',				'Lao kip',				'LAK',	'\u20AD' ],
['Latvia',				'Latvian lat',			'LVL',	'Ls' ],
['Lebanon',				'Lebanese pound',			'LBP',	'\u00A3','\u0644.\u0644' ],
['Lesotho',				'Lesotho loti',			'LSL',	'L' ],
['Liberia',				'Liberian dollar',			'LRD',	'$' ],
['Libya',				'Libyan dinar',			'LYD',	'\u0644.\u062F' ],
['Liechtenstein',			'Swiss franc',			'CHF',	'S\u20A3','Fr.' ],
['Lithuania',				'Lithuanian litas',			'LTL',	'Lt' ],
['Luxembourg',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Macau',				'Macanese pataca',			'MOP',	'P' ],
['Macedonia, Republic of',		'Macedonian denar',			'MKD',	'\u0434\u0435\u043D' ],
['Madagascar',				'Malagasy ariary',			'MGA',	'Fmg' ],
['Malawi',				'Malawian kwacha',			'MWK',	'MK' ],
['Malaysia',				'Malaysian Ringgit',			'MYR',	'RM' ],
['Maldives',				'Maldives rufiyaa',			'MVR',	'\u0783.' ],
['Mali',				'CFA franc BCEAO',			'XOF',	'Fr' ],
['Malta',				'Maltese lira',			'MTL',	'\u20A4' ],
['Marshall Islands',			'United States dollar',			'USD',	'$','dollars','US$','US $' ],
['Mauritania',				'Mauritanian ouguiya',			'MRO',	'UM' ],
['Mauritius',				'Mauritian rupee',			'MUR',	'\u20A8' ],
['Mexico',				'Mexican peso',			'MXN',	'$' ],
['Micronesia',				'United States dollar',			'USD',	'$','dollars','US$','US $' ],
['Moldova',				'Moldovan leu',			'MDL',	'L' ],
['Monaco',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Mongolia',				'Mongolian tugrik',			'MNT',	'\u20AE' ],
['Montenegro',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Montserrat',				'East Caribbean dollar',		'XCD',	'$' ],
['Morocco',				'Moroccan dirham',			'MAD',	'\u062F.\u0645.' ],
['Mozambique',				'Mozambican metical',			'MZM',	'Mt' ],
['Myanmar',				'Myanmar kyat',			'MMK',	'K' ],
['Namibia',				'Namibian dollar',			'NAD',	'$' ],
['Nauru',				'Australian dollar',			'AUD',	'$','A$','AU $' ],
['Nepal',				'Nepalese rupee',			'NPR',	'\u20A8' ],
['Netherlands',			'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Netherlands Antilles',			'Netherlands Antillean gulden',		'ANG',	'\u0192' ],
['New Caledonia',			'CFP franc',				'XPF',	'\u20A3' ],
['New Zealand',			'New Zealand dollar',			'NZD',	'$' ],
['Nicaragua',				'Nicaraguan gold c\u00F3rdoba',		'NIO',	'$' ],
['Niger',				'CFA franc BCEAO',			'XOF',	'Fr' ],
['Nigeria',				'Nigerian naira',			'NGN',	'\u20A6' ],
['Norway',				'Norwegian krone',			'NOK',	'kr','kr.' ],
['Oman',				'Omani rial',				'OMR',	'\u0631.\u0639.' ],
['Pakistan',				'Pakistani rupee',			'PKR',	'\u20A8' ],
['Palau',				'United States dollar',			'USD',	'$','dollars','US$','US $' ],
['Palestine',				'New Israeli shekel',			'ILS',	'\u20AA' ],
['Panama',				'Panamanian balboa',			'PAB',	'B/.' ],
['Papua New Guinea',			'Papua New Guinea kina',		'PGK',	'K' ],
['Paraguay',				'Paraguayan guaran\u00ED',		'PYG',	'\u20B2' ],
['Peru',				'Peruvian nuevo sol',			'PEN',	'S/.' ],
['Philippines',			'Philippine peso',			'PHP',	'\u20B1' ],
['Pitcairn Islands',			'New Zealand dollar',			'NZD',	'$' ],
['Poland',				'Polish z\u0142oty',			'PLN',	'z\u0142' ],
['Portugal',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Qatar',				'Qatari riyal',			'QAR',	'\u0631.\u0642' ],
['Romania',				'New Romanian leu',			'RON',	'lei' ],
['Russia',				'Russian rouble',			'RUB',	'\u0440.','\u0440' ],
['Rwanda',				'Rwandan franc',			'RWF',	'Fr' ],
['Saint Helena',			'Saint Helenian pound',			'SHP',	'\u00A3' ],
['Saint Kitts and Nevis',		'East Caribbean dollar',		'XCD',	'$' ],
['Saint Lucia',			'East Caribbean dollar',		'XCD',	'$' ],
['Saint Vincent and the Grenadines',	'East Caribbean dollar',		'XCD',	'$' ],
['Samoa',				'Samoan tala',			'WST',	'S$' ],
['San Marino',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['S\u00E3o Tom\u00E9 and Pr\u00EDncipe',	'S\u00E3o Tom\u00E9 and Pr\u00EDncipe dobra','STD',	'Db' ],
['Saudi Arabia',			'Saudi riyal',			'SAR',	'\u0631.\u0633' ],
['Senegal',				'CFA franc BCEAO',			'XOF',	'Fr' ],
['Serbia',				'Serbian dinar',			'CSD',	'Din.','\u0414\u0418\u041D' ],
['Seychelles',				'Seychelles rupee',			'SCR',	'\u20A8' ],
['Sierra Leone',			'Sierra Leonean leone',			'SLL',	'Le' ],
['Singapore',				'Singapore dollar',			'SGD',	'$' ],
['Slovakia',				'Slovak koruna',			'SKK',	'Sk' ],
['Slovenia',				'Euro',			                'EUR',	'\u20AC','euros','euro' ],
['Solomon Islands',			'Solomon Islands dollar',		'SBD',	'$' ],
['Somalia',				'Somali shilling',			'SOS',	'So. Sh.' ],
['South Africa',			'South African rand',			'ZAR',	'R' ],
['Spain',				'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Sri Lanka',				'Sri Lankan rupee',			'LKR',	'\u0BB0\u0BC2' ],
['Sudan',				'Sudanese dinar',			'SDD',	'LSd' ],
['Suriname',				'Suriname dollar',			'SRD',	'$' ],
['Swaziland',				'Swazi lilangeni',			'SZL',	'L' ],
['Sweden',				'Swedish krona',			'SEK',	'kr','kr.' ],
['Switzerland',			'Swiss franc',			'CHF',	'S\u20A3','Fr.' ],
['Syria',				'Syrian pound',			'SYP',	'\u00A3','\u0644.\u0633' ],
['Taiwan',		'New Taiwan dollar',			'TWD',	'\u5713','$' ],
['Tajikistan',				'Tajikistani somoni',			'TJS',	'\u0405\u041C' ],
['Tanzania',				'Tanzanian shilling',			'TZS',	'Tsh' ],
['Thailand',				'Thai baht',				'THB',	'\u0E3F' ],
['Togo',				'CFA franc BCEAO',			'XOF',	'Fr' ],
['Tonga',				'Tongan pa\'anga',			'TOP',	'T$' ],
['Trinidad and Tobago',			'Trinidad and Tobago dollar',		'TTD',	'$' ],
['Tunisia',				'Tunisian dinar',			'TND',	'\u062F.\u062A' ],
['Turkey',				'New Turkish lira',			'TRY',	'\u20A4' ],
['Turkmenistan',			'Turkmen manat',			'TMM',	'manat' ],
['Turks and Caicos Islands',		'United States dollar',			'USD',	'$','dollars','US$','US $' ],
['Uganda',				'Ugandan shilling',			'UGX',	'Ush' ],
['Ukraine',				'Ukrainian hryvnia',			'UAH',	'\u20B4' ],
['United Arab Emirates',			'United Arab Emirates dirham',		'AED',	'\u062F.\u0625' ],
['United Kingdom',			'British pound',			'GBP',	'\u00A3','quid' ],
['United States',			'United States dollar',			'USD',	'$','dollars','US$','US $' ],
['Uruguay',				'Uruguayan peso',			'UYU',	'$','\u20B1' ],
['Uzbekistan',				'Uzbekistani som',			'UZS',	'su\u2019m','\u0441\u045E\u043C' ],
['Vanuatu',				'Vanuatu vatu',			'VUV',	'VT' ],
['Vatican City',			'Euro',				'EUR',	'\u20AC','euros','euro' ],
['Venezuela',				'Venezuelan bol\u00EDvar',		'VEB',	'Bs' ],
['Vietnam',				'Vietnamese dong',			'VND',	'\u20AB' ],
['Wallis and Futuna',			'CFP franc',				'XPF',	'\u20A3' ],
['Yemen',				'Yemeni rial',			'YER',	'\u0631\u064A\u0627\u0644' ],
['Zambia',				'Zambian kwacha',			'ZMK',	'ZK' ],
['Zimbabwe',				'Zimbabwean dollar',			'ZWD',	'$' ]
     ];

// Final exchange rates from http://en.wikipedia.org/wiki/Euro
var euroZoneCurrencies =
  [
   ['Austria',        'Austrian Schilling',    'ATS',	'OS',			'=13.7603 EUR'  ],
   ['Belgium',	      'Belgian Franc',         'BEF',   'BFr','BFr.',		'=40.3399 EUR'  ],
   ['Finland',	      'Finish Markka',         'FIM',	'mk',			'=5.94573 EUR'  ],
   ['France',	      'French Franc',	       'FRF',   '\u20A3','Fr','Fr.',	'=6.55957 EUR'  ],
   ['Germany',	      'German Deutsche Mark',  'DEM',	'DM',			'=1.95583 EUR'  ],
   ['Greece',	      'Greek Drachma',         'GRD',   '\u20AF',		'=340.750 EUR'  ],
   ['Netherlands',    'Dutch Guilder',         'NLG',   '\u0192','fl.',	        '=2.20371 EUR'  ],
   ['Ireland',	      'Irish Pound',	       'IEP',   'IR\u00A3',		'=0.787564 EUR' ],
   ['Italy',	      'Italian Lira',	       'ITL',	'\u20A4',		'=1936.27 EUR'  ],
   ['Luxembourg',     'Luxembourgian Franc',   'LUF',   'LFr',			'=40.3399 EUR'  ],
   ['Portugal',	      'Portuguese  Escudo',    'PTE',   'escudo',		'=200.482 EUR'  ],
   ['Slovenia',       'Slovenian tolar',       'SIT',	'tolar',                '=239.640 EUR'  ],
   ['Spain',	      'Spanish Peseta',        'ESP',   '\u20A7',		'=166.386 EUR'  ],
   ['Vatican City',   'Vatican City Lira',     'VAL',   '\u20A4',		'=1936.27 EUR'  ]
   ];

  var notSupportedCodes =VMC.webServiceList.notSupportedCodes;

  var isSupported = function(code) {
    for (var j=0;j<notSupportedCodes.length;j++) {
      if (notSupportedCodes[j]==code) { return false; }
    }
    return true;
  };


  var currencies = currentCurrencies.concat(euroZoneCurrencies).sort();

  var symbolTable  = (this._completeSymbolTable  = new VMC.SymbolTable([])  );
  var currencyList = (this._completeCurrencyList = new VMC.CurrencyList([]) );

  var toEachLine = function(line) {
    var country=line[0];
    var description=line[1];
    var code=line[2];
    var symbols=line.slice(3); //all the rest
    var formula = null;
    if ( symbols[symbols.length-1][0] == '=' ) { // last symbol, first char is =
      formula = symbols.pop(); // the last symbol was actually a formula
    }
    symbols.push(code); // include the currency code as a symbol
    var dspSymbol = symbols[0]; // the symbol used to display the converted amount defaults to the first symbol

    if (includeNotSupported || isSupported(code)) {
      var currency = new VMC.Currency(country,description,code,dspSymbol,formula);
      var symbolList = new VMC.SymbolList(symbols);
      var symbolTableEntry = new VMC.SymbolTableEntry(currency,symbolList);
      currencyList.add(currency, true /*allowDups*/ );
      symbolTable.add(symbolTableEntry);
    } else {
      //dump('skipping '+code+'\n');
    }
  };
  VMC.applyFuncToArray(toEachLine,currencies);


  this.getCompleteList = function(includeNotSupported) { //WILL: TODO: support includeNotSupported ?? ,   don't change the contents!
    return this._completeCurrencyList;
  };


// The following countries have no supported currency
//
// Antarctica
// American Samoa
// Aland Islands
// Bouvet Island
// Christmas Island
// Western Sahara
// Falklands Islands
// Faroe Islands
// French Guiana
// Greenland
// Guadeloupe
// South Georgia and the South Sandwich Islands
// Guam
// Heard Island and McDonald Islands
// Northern Mariana Islands
// Martinique
// Norfolk Island
// Niue
// Saint Pierre and Miquelon
// Pitcairn
// Puerto Rico
// R\u00E9union
// Svalbard and Jan Mayen
// Sao Tome and Principe
// French Southern Territories
// Tokelau
// Timor-Leste
// Tuvalu
// United States Minor Outlying Islands
// Virgin Islands, U.S.
// Mayotte


//Alpha-2 	English country name 	Notes

this.countryCode2CountryName = {
'AD':'Andorra',
'AE':'United Arab Emirates',
'AF':'Afghanistan',
'AG':'Antigua and Barbuda',
'AI':'Anguilla',
'AL':'Albania',
'AM':'Armenia',
'AN':'Netherlands Antilles',
'AO':'Angola',
'AQ':'Antarctica',
'AR':'Argentina',
'AS':'American Samoa',
'AT':'Austria',
'AU':'Australia',
'AW':'Aruba',
'AX':'\u00C5land Islands',
'AZ':'Azerbaijan',
'BA':'Bosnia and Herzegovina',
'BB':'Barbados',
'BD':'Bangladesh',
'BE':'Belgium',
'BF':'Burkina Faso',
'BG':'Bulgaria',
'BH':'Bahrain',
'BI':'Burundi',
'BJ':'Benin',
'BM':'Bermuda',
'BN':'Brunei',
'BO':'Bolivia',
'BR':'Brazil',
'BS':'Bahamas',
'BT':'Bhutan',
'BV':'Bouvet Island',
'BW':'Botswana',
'BY':'Belarus',
'BZ':'Belize',
'CA':'Canada',
'CC':'Cocos (Keeling) Islands',
'CD':'Congo, Democratic Republic of the',
'CF':'Central African Republic',
'CG':'Congo, Republic of the',
'CH':'Switzerland',
'CI':'C\u00F4te d\'Ivoire',
'CK':'Cook Islands',
'CL':'Chile',
'CM':'Cameroon',
'CN':'China, People\'s Republic of',
'CO':'Colombia',
'CR':'Costa Rica',
'CS':'Serbia',
'CU':'Cuba',
'CV':'Cape Verde',
'CX':'Christmas Island',
'CY':'Cyprus',
'CZ':'Czech Republic',
'DE':'Germany',
'DJ':'Djibouti',
'DK':'Denmark',
'DM':'Dominica',
'DO':'Dominican Republic',
'DZ':'Algeria',
'EC':'Ecuador',
'EE':'Estonia',
'EG':'Egypt',
'EH':'Western Sahara',
'ER':'Eritrea',
'ES':'Spain',
'ET':'Ethiopia',
'FI':'Finland',
'FJ':'Fiji',
'FK':'Falkland Islands',
'FM':'Micronesia',
'FO':'Faroe Islands',
'FR':'France',
'GA':'Gabon',
'GB':'United Kingdom',
'GD':'Grenada',
'GE':'Georgia',
'GF':'French Guiana',
'GH':'Ghana',
'GI':'Gibraltar',
'GL':'Greenland',
'GM':'Gambia, The',
'GN':'Guinea',
'GP':'Guadeloupe',
'GQ':'Equatorial Guinea',
'GR':'Greece',
'GS':'South Georgia and the South Sandwich Islands',
'GT':'Guatemala',
'GU':'Guam',
'GW':'Guinea Bissau',
'GY':'Guyana',
'HK':'Hong Kong',
'HM':'Heard Island and McDonald Islands',
'HN':'Honduras',
'HR':'Croatia',
'HT':'Haiti',
'HU':'Hungary',
'ID':'Indonesia',
'IE':'Ireland, Republic of',
'IL':'Israel',
'IN':'India',
'IO':'British Indian Ocean Territory',
'IQ':'Iraq',
'IR':'Iran',
'IS':'Iceland',
'IT':'Italy',
'JM':'Jamaica',
'JO':'Jordan',
'JP':'Japan',
'KE':'Kenya',
'KG':'Kyrgyzstan',
'KH':'Cambodia',
'KI':'Kiribati',
'KM':'Comoros',
'KN':'Saint Kitts and Nevis',
'KP':'Korea, North',
'KR':'Korea, South',
'KW':'Kuwait',
'KY':'Cayman Islands',
'KZ':'Kazakhstan',
'LA':'Laos',
'LB':'Lebanon',
'LC':'Saint Lucia',
'LI':'Liechtenstein',
'LK':'Sri Lanka',
'LR':'Liberia',
'LS':'Lesotho',
'LT':'Lithuania',
'LU':'Luxembourg',
'LV':'Latvia',
'LY':'Libya',
'MA':'Morocco',
'MC':'Monaco',
'MD':'Moldova',
'MG':'Madagascar',
'MH':'Marshall Islands',
'MK':'Macedonia, Republic of',
'ML':'Mali',
'MM':'Myanmar',
'MN':'Mongolia',
'MO':'Macau',
'MP':'Northern Mariana Islands',
'MQ':'Martinique',
'MR':'Mauritania',
'MS':'Montserrat',
'MT':'Malta',
'MU':'Mauritius',
'MV':'Maldives',
'MW':'Malawi',
'MX':'Mexico',
'MY':'Malaysia',
'MZ':'Mozambique',
'NA':'Namibia',
'NC':'New Caledonia',
'NE':'Niger',
'NF':'Norfolk Island',
'NG':'Nigeria',
'NI':'Nicaragua',
'NL':'Netherlands',
'NO':'Norway',
'NP':'Nepal',
'NR':'Nauru',
'NU':'Niue',
'NZ':'New Zealand',
'OM':'Oman',
'PA':'Panama',
'PE':'Peru',
'PF':'French Polynesia',
'PG':'Papua New Guinea',
'PH':'Philippines',
'PK':'Pakistan',
'PL':'Poland',
'PM':'Saint Pierre and Miquelon',
'PN':'Pitcairn',
'PR':'Puerto Rico',
'PS':'Palestine',
'PT':'Portugal',
'PW':'Palau',
'PY':'Paraguay',
'QA':'Qatar',
'RE':'R\u00E9union',
'RO':'Romania',
'RU':'Russia',
'RW':'Rwanda',
'SA':'Saudi Arabia',
'SB':'Solomon Islands',
'SC':'Seychelles',
'SD':'Sudan',
'SE':'Sweden',
'SG':'Singapore',
'SH':'Saint Helena',
'SI':'Slovenia',
'SJ':'Svalbard and Jan Mayen',
'SK':'Slovakia',
'SL':'Sierra Leone',
'SM':'San Marino',
'SN':'Senegal',
'SO':'Somalia',
'SR':'Suriname',
'ST':'Sao Tome and Principe',
'SV':'El Salvador',
'SY':'Syria',
'SZ':'Swaziland',
'TC':'Turks and Caicos Islands',
'TD':'Chad',
'TF':'French Southern Territories',
'TG':'Togo',
'TH':'Thailand',
'TJ':'Tajikistan',
'TK':'Tokelau',
'TL':'Timor-Leste',
'TM':'Turkmenistan',
'TN':'Tunisia',
'TO':'Tonga',
'TR':'Turkey',
'TT':'Trinidad and Tobago',
'TV':'Tuvalu',
'TW':'Taiwan',
'TZ':'Tanzania',
'UA':'Ukraine',
'UG':'Uganda',
'UM':'United States Minor Outlying Islands',
'US':'United States',
'UY':'Uruguay',
'UZ':'Uzbekistan',
'VA':'Vatican City',
'VC':'Saint Vincent and the Grenadines',
'VE':'Venezuela',
'VG':'British Virgin Islands',
'VI':'Virgin Islands, U.S.',
'VN':'Vietnam',
'VU':'Vanuatu',
'WF':'Wallis and Futuna',
'WS':'Samoa',
'YE':'Yemen',
'YT':'Mayotte',
'ZA':'South Africa',
'ZM':'Zambia',
'ZW':'Zimbabwe'
};

this.createListFromCountry = function(country,failSilently) {
  var currencies = new VMC.CurrencyList();
    var compareByCountry = function(currency) { if (currency.country==country) { currencies.add(currency); } }; 
    this._completeCurrencyList._applyFunc(compareByCountry);
  if (!VMC.CurrencyList.prototype.isValid(currencies,failSilently) && !failSilently) {VMC.log('ERR','Could not find '+country+' in '+this); }
    return currencies;
};
  
this.createListFromCountries = function(countryList) {
  var foundCurrencies = new VMC.CurrencyList();
    for (var i=0;i<countryList.length;i++) {
      var currencies = this.createListFromCountry(countryList[i]);
      foundCurrencies.addList(currencies);
    }
    return foundCurrencies;
};

//  http://wiki.mozilla.org/L10n:Simple_locale_names
//     * ab
//     * ab-XY
//     * abc-XY
//     * abc-XY-SIL
//     * abc-XY-dialect 
// where
//     * ab/abc - from ISO 639.1/639.2 (http://www.loc.gov/standards/iso639-2/)
//     * XY - from ISO 3166 (http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html)
//     * SIL - from the SIL list (http://www.ethnologue.com/codes/)
//     * dialect - following the rules from RFC 3066 (3 to 8 characters) 

// http://lxr.mozilla.org/l10n/find?string=browser-region%2Fregion.properties
// ab forms: ca,  bg, ar, cs, de, ru, sl, fr, el, hu, it, pl, nl, fi, he, ja, ro, eu, da, mk, sq, tr, ko, mn, sk, 
// abc-XY  : nn-NO, pt-BR, fy-NL, hy-AM, zh-TW, zh-CN, es-ES, pa-IN, en-GB, gu-IN, sv-SE, ga-IE, es-AR, nb-NO,
// abc-XY-x: ja-JP-mac

// returns a list of possible currencies based on language
this.findFromLocale = function(locale,failSilently) {
    if (!locale) { VMC.log('ERR','Null locale'); return null; }
    var countryCodes=[];
    var currencyList = new VMC.CurrencyList();

    var r=locale.split('-');

    //Arabic -> Algeria, Bahrain, Egypt, Iraq, Jordan, Kuwait, Lebanon, Libya, Mauritania, Morocco, Oman, Qatar,
    //          Saudi Arabia, Somalia, Sudan, Syria, Tunisia, United Arab Emirates, Palestine, Yemen
    if (!r || r.length<2) {   // Locale is not in two or three parts,
      switch(locale) {
      case 'ca' : countryCodes.push('ES'); break; // Catalan ->  Spain
      case 'ar' : countryCodes.push('DZ','BH','EG','IQ','IR','JO','KW','LB','MR','MA','OM','QA','SA','SO','SD','SY','TN','AE','PS','YE'); break;
      case 'cs' : countryCodes.push('CZ'); break; // Czech -> Czech Republic
      case 'sl' : countryCodes.push('SI'); break; // Slovenian -> Slovenia
      case 'el' : countryCodes.push('GR'); break; // Greek -> Greece
      case 'en' : countryCodes.push('US','GB'); break; // English -> USA, UK
      case 'nl' : countryCodes.push('NL','BE'); break; // Dutch --> Nederlands, Belgium
      case 'et' : countryCodes.push('EE'); break; // Estonian -> Estonia
      case 'he' : countryCodes.push('IL'); break; // Hebrew -> Israel
      case 'ja' : countryCodes.push('JP'); break; // Japanese -> Japan
      case 'eu' : countryCodes.push('ES'); break; // Basque -> Spain
      case 'da' : countryCodes.push('DK'); break; // Danish -> Denmark
      case 'sq' : countryCodes.push('AL'); break; // Albanian -> Albania
      case 'ko' : countryCodes.push('KR'); break; // Korean -> Korea, South
      default   : countryCodes.push(locale);      // assume that the simple language code is the same as the country code.
      }
    } else {
      countryCodes.push(r[1]);
    }
    for (var i=0;i<countryCodes.length;i++) {
      var countryCode=countryCodes[i];
      var countryName=this.countryCode2CountryName[countryCode.toUpperCase()];    
      if (!countryName && !failSilently) { VMC.log('ERR','Unknown country code ['+countryCode+']'); return null;}
      var currencies=this.createListFromCountry(countryName,failSilently);
      if (VMC.CurrencyList.prototype.isValid(currencies, true)) { currencyList.addList(currencies, false, true); } /* no dups, failSilently */
    }
    return currencyList;
};

  this.createListFromLanguages = function(acceptLanguages) {
    var localeCurrencyList = new VMC.CurrencyList();
    acceptLanguages = acceptLanguages.replace(/\s+/g,''); //remove all whitespace
    acceptLanguages = acceptLanguages.toLowerCase();

    var locales = acceptLanguages.split(',');
    for (var i=0;i<locales.length;i++) {
      var currencyList = this.findFromLocale(locales[i], true); //failSilently //TODO: deal with failure?
      localeCurrencyList.addList(currencyList, false, true); //do not allow duplicates, but don't complain if we try to add them
    }
    var defaultCountries = ['United States','Eurozone','United Kingdom'];
    var defaultList = this.createListFromCountries(defaultCountries); //always include these major currencies
    localeCurrencyList.addList(defaultList, false, true);
    return localeCurrencyList;
  };

  this.generateDefaultSymbolTableFor = function(currencyList) {
    var completeSymbolTable = this._completeSymbolTable;
    var newSymbolTable      = new VMC.SymbolTable([]);

    var toEachCurrency = function(currency) {
      var tableEntry = completeSymbolTable.lookupCurrency(currency);
      newSymbolTable.add(tableEntry);
    };
    currencyList._applyFunc(toEachCurrency);

    return newSymbolTable;
  };

}; // end of CurrencyDataBase




VMC.currencyDB = new VMC.CurrencyDataBase();


////////////////////////////////////////////////////////////////////////////////

//WILL: currently the ConversionProfile just stores a symboltable, maybe later I will add stuff like formatting hints
////////////////////////////////////////////////////////////////////////////////
VMC.ConversionProfile = function(symbolTable) {
////////////////////////////////////////////////////////////////////////////////
  this.findCurrencyFromStr = function(str) {
    return symbolTable.matches(str);
  };

  this.getLeftRE = function() { 
    if (!symbolTable.currencyLeftRE) { symbolTable.createRegExps(); }
    return symbolTable.currencyLeftRE;
  };

  this.getRightRE = function() { 
    if (!symbolTable.currencyRightRE) { symbolTable.createRegExps(); }
    return symbolTable.currencyRightRE;
  };

  this.toString = function() { return '     new ConversionProfile('+symbolTable+')'; };

};


////////////////////////////////////////////////////////////////////////////////
VMC.ConversionProfileTableEntry = function(description,regexps,profile) {
////////////////////////////////////////////////////////////////////////////////
  this.profile = profile;
  this.description = description;
  this.regexps = regexps;
  this.toString = function() { return '  new ConversionProfileTableEntry("'+description+'", ['+regexps+'],\n '+profile+')'; };
  this.isDefault = (this.regexps == null || this.regexps[0] == null)  // if no regexps then we are the default profile
  // ( regexps can be [null] array if constructed from serialised object )
};

VMC.ConversionProfileTableEntry.prototype.matches = function(url) {
    if (this.isDefault) { return true; } // default profile matches everything
    url = url.toLowerCase();
    var toEachRE = function(regExp) { return regExp.test(url) ? true : undefined; }; // undefined stops premature return of applyFuncToArray
    return VMC.applyFuncToArray(toEachRE,this.regexps) ? true : false;
};

////////////////////////////////////////////////////////////////////////////////
VMC.ConversionProfileTable = function(list) {
////////////////////////////////////////////////////////////////////////////////
  this.entries = list;
  this._activeProfileEntry = null; // which profile are we using for the current web page?
};


VMC.ConversionProfileTable.prototype.setActiveProfileEntryToDefault = function() {
   var toEachEntry = function(entry) { return entry.isDefault ? entry : undefined; };
   var defaultEntry = VMC.applyFuncToArray(toEachEntry,this.entries);
   if (!defaultEntry) { VMC.log('ERR','Could not find default profile'); }
   this._activeProfileEntry = defaultEntry;
};
   
VMC.ConversionProfileTable.prototype.setActiveProfileEntryForUrl = function(url) {
  this._activeProfileEntry = this.getMatching(url);
  VMC.log('DBG',this._activeProfileEntry.toString(false)+' \t '+url);
  return this._activeProfileEntry;
};

VMC.ConversionProfileTable.prototype.getMatching = function(url) {
  var toEachEntry = function(entry) { return entry.matches(url) ? entry : undefined; }; // undefined stops premature return of applyFuncToArray
  var matchingEntry = VMC.applyFuncToArray(toEachEntry,this.entries);
  if (!matchingEntry) { VMC.log('ERR','Could not find a matching profile for URL: '+url); }
  return matchingEntry;
};

VMC.ConversionProfileTable.prototype.findCurrencyFromStr = function(str) {
  var conversionProfile = this._activeProfileEntry.profile;
  if (!conversionProfile) {
    return null; //the exclucedEntry does not have a profile
  } else {
    return conversionProfile.findCurrencyFromStr(str);
  }
};
  
VMC.ConversionProfileTable.prototype.toString = function() { return 'new ConversionProfileTable([\n'+this.entries.join(',\n')+'\n])'; };


//WILL: reuse existing table functions
VMC.ConversionProfileTable.prototype._validPosition = VMC.SymbolTable.prototype._validPosition;
VMC.ConversionProfileTable.prototype.move   = VMC.SymbolTable.prototype.move;
VMC.ConversionProfileTable.prototype.remove = VMC.SymbolTable.prototype.remove;
VMC.ConversionProfileTable.prototype.add    = VMC.SymbolTable.prototype.add;

      





